package tse

import (
	"gitee.com/amoyx/cloud-provider/pkg/cloud/tencent/models"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	tdmq "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq/v20200217"
	trocket "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/trocket/v20230308"
	"strconv"
	"strings"
)

type RocketMQGreeter interface {
	RocketMQ(region string) RocketMQInterface
}

type RocketMQInterface interface {
	CreateInstanceV5(args models.RocketMQRequest) (result models.CreateResponseParams, err error)
	DeleteInstanceV5(id string) (err error)
	ListAllV5() (list []models.RocketMQItem, err error)
	DescribeInstanceV5(id string) (result models.RocketMQItem, err error)
	CreateInstanceV4(args models.RocketMQRequestV4) (result models.CreateResponseParams, err error)
	DescribeInstanceV4(id string) (result models.RocketMQItem, err error)
	DeleteInstanceV4(id string) (err error)
	ListByNameV4(name string) (list []models.RocketMQItem, err error)
	ListAllV4() (list []models.RocketMQItem, err error)
	DescribeInstanceShare(id string) (result models.RocketMQItemV4, err error)
	ListByNameShare(name string) (list []models.RocketMQItemV4, err error)
	ListAllShare() (list []models.RocketMQItemV4, err error)
	DeleteShareInstance(id string) (err error)
	CreateShareInstance(name string) (result models.CreateResponseParams, err error)
}

type rocketmq struct {
	tse      *TSE
	region   string
	clientV5 *trocket.Client
	clientV4 *tdmq.Client
}

func newRocketMQ(tse *TSE, region string) RocketMQInterface {
	v := &rocketmq{
		tse:    tse,
		region: region,
	}
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = string(RocketMQEndPoint)
	client5, _ := trocket.NewClient(v.tse.Credential(), v.region, cpf)
	v.clientV5 = client5

	cpf2 := profile.NewClientProfile()
	cpf2.HttpProfile.Endpoint = string(TDMQEndPoint)
	client4, _ := tdmq.NewClient(v.tse.Credential(), v.region, cpf2)
	v.clientV4 = client4
	return v
}

func (r *rocketmq) CreateInstanceV4(args models.RocketMQRequestV4) (result models.CreateResponseParams, err error) {
	request := tdmq.NewCreateRocketMQVipInstanceRequest()
	request.Name = common.StringPtr(args.Name)
	request.Spec = common.StringPtr(args.Spec)
	request.NodeCount = common.Int64Ptr(args.NodeCount)
	request.StorageSize = common.Int64Ptr(args.StorageSize)
	request.ZoneIds = common.StringPtrs([]string{args.ZoneId})
	request.VpcInfo = &tdmq.VpcInfo{
		VpcId:    common.StringPtr(args.VpcId),
		SubnetId: common.StringPtr(args.SubnetId),
	}
	request.TimeSpan = common.Int64Ptr(args.TimeSpan)
	response, err := r.clientV4.CreateRocketMQVipInstance(request)
	if err != nil {
		return
	}
	res := response.Response
	result.RequestId = *res.RequestId
	result.InstanceSet = append(result.InstanceSet, *res.ClusterId)
	return
}

func (r *rocketmq) DeleteInstanceV4(id string) (err error) {
	request := tdmq.NewDeleteRocketMQVipInstanceRequest()
	request.ClusterId = common.StringPtr(id)
	_, err = r.clientV4.DeleteRocketMQVipInstance(request)
	return
}

func (r *rocketmq) CreateInstanceV5(args models.RocketMQRequest) (result models.CreateResponseParams, err error) {
	request := trocket.NewCreateInstanceRequest()
	request.InstanceType = common.StringPtr(args.InstanceType)
	request.Name = common.StringPtr(args.Name)
	request.SkuCode = common.StringPtr(args.SkuCode)
	request.Remark = common.StringPtr(args.Remark)
	request.EnablePublic = common.BoolPtr(false)
	request.MessageRetention = common.Int64Ptr(args.MessageRetention)
	request.VpcList = []*trocket.VpcInfo{
		&trocket.VpcInfo{
			VpcId:    common.StringPtr(args.VpcId),
			SubnetId: common.StringPtr(args.SubnetId),
		},
	}
	response, err := r.clientV5.CreateInstance(request)
	res := response.Response
	if err != nil {
		return
	}
	result.RequestId = *res.RequestId
	result.InstanceSet = append(result.InstanceSet, *res.InstanceId)
	return
}

func (r *rocketmq) CreateShareInstance(name string) (result models.CreateResponseParams, err error) {
	request := tdmq.NewCreateRocketMQClusterRequest()
	request.Name = common.StringPtr(name)
	request.Remark = common.StringPtr("rocketmq共享集群")
	response, err := r.clientV4.CreateRocketMQCluster(request)
	if err != nil {
		return
	}
	res := response.Response
	result.RequestId = *res.RequestId
	result.InstanceSet = append(result.InstanceSet, *res.ClusterId)
	return
}

func (r *rocketmq) DeleteShareInstance(id string) (err error) {
	request := tdmq.NewDeleteRocketMQClusterRequest()
	request.ClusterId = common.StringPtr(id)
	_, err = r.clientV4.DeleteRocketMQCluster(request)
	return
}

func (r *rocketmq) DeleteInstanceV5(id string) (err error) {
	request := trocket.NewDeleteInstanceRequest()
	request.InstanceId = common.StringPtr(id)
	_, err = r.clientV5.DeleteInstance(request)
	return
}

func (r *rocketmq) DescribeInstanceV5(id string) (result models.RocketMQItem, err error) {
	list, err := r.query(map[string]string{"InstanceId": id})
	if len(list) > 0 {
		result = list[0]
	}
	return
}

func (r *rocketmq) ListAllV5() (list []models.RocketMQItem, err error) {
	return r.query(map[string]string{})
}

func (r *rocketmq) query(args map[string]string) (list []models.RocketMQItem, err error) {
	request := trocket.NewDescribeInstanceListRequest()
	var filters []*trocket.Filter
	for key, val := range args {
		filters = append(filters, &trocket.Filter{
			Name:   common.StringPtr(key),
			Values: common.StringPtrs([]string{val}),
		})
	}
	request.Offset = common.Int64Ptr(0)
	request.Limit = common.Int64Ptr(1000)
	response, err := r.clientV5.DescribeInstanceList(request)
	if err != nil {
		return
	}
	for _, row := range response.Response.Data {
		list = append(list, models.RocketMQItem{
			InstanceId:       *row.InstanceId,
			InstanceName:     *row.InstanceName,
			Version:          *row.Version,
			InstanceType:     *row.InstanceType,
			InstanceStatus:   *row.InstanceStatus,
			TopicNumLimit:    *row.TopicNumLimit,
			GroupNumLimit:    *row.GroupNumLimit,
			PayMode:          *row.PayMode,
			ExpiryTime:       *row.ExpiryTime,
			Remark:           *row.Remark,
			TopicNum:         *row.TopicNum,
			GroupNum:         *row.GroupNum,
			SkuCode:          *row.SkuCode,
			TpsLimit:         *row.TpsLimit,
			ScaledTpsLimit:   *row.ScaledTpsLimit,
			MessageRetention: *row.MessageRetention,
			MaxMessageDelay:  *row.MaxMessageDelay,
		})
	}
	return
}

func (r *rocketmq) DescribeInstanceV4(id string) (result models.RocketMQItem, err error) {
	list, err := r.queryV4(map[string]string{"InstanceId": id})
	if len(list) > 0 {
		result = list[0]
	}
	return
}

func (r *rocketmq) ListByNameV4(name string) (list []models.RocketMQItem, err error) {
	return r.queryV4(map[string]string{"InstanceName": name})
}

func (r *rocketmq) ListAllV4() (list []models.RocketMQItem, err error) {
	return r.queryV4(map[string]string{})
}

func (r *rocketmq) DescribeInstanceShare(id string) (result models.RocketMQItemV4, err error) {
	list, err := r.queryShare(id, "")
	if len(list) > 0 {
		result = list[0]
	}
	return
}

func (r *rocketmq) ListByNameShare(name string) (list []models.RocketMQItemV4, err error) {
	return r.queryShare("", name)
}

func (r *rocketmq) ListAllShare() (list []models.RocketMQItemV4, err error) {
	return r.queryShare("", "")
}

func (r *rocketmq) queryV4(args map[string]string) (list []models.RocketMQItem, err error) {
	request := tdmq.NewDescribeRocketMQVipInstancesRequest()
	var filters []*tdmq.Filter
	for key, val := range args {
		filters = append(filters, &tdmq.Filter{
			Name:   common.StringPtr(key),
			Values: common.StringPtrs([]string{val}),
		})
	}
	request.Filters = filters
	request.Offset = common.Uint64Ptr(0)
	request.Limit = common.Uint64Ptr(1000)
	response, err := r.clientV4.DescribeRocketMQVipInstances(request)
	if err != nil {
		return
	}
	for _, row := range response.Response.Instances {
		var expiry64 int64
		expiry := strconv.FormatUint(*row.ExpireTime, 10)
		if tmp, err := strconv.ParseInt(expiry, 10, 64); err != nil {
			expiry64 = tmp
		}
		list = append(list, models.RocketMQItem{
			InstanceId:       *row.InstanceId,
			InstanceName:     *row.InstanceName,
			Version:          *row.InstanceVersion,
			InstanceStatus:   strconv.FormatUint(*row.Status, 10),
			PayMode:          strconv.FormatUint(*row.PayMode, 10),
			ExpiryTime:       expiry64,
			Remark:           *row.Remark,
			SkuCode:          *row.SpecName,
			MessageRetention: *row.MinRetention,
			MaxMessageDelay:  *row.MaxRetention,
		})
	}
	return
}

func (r *rocketmq) queryShare(id string, name string) (list []models.RocketMQItemV4, err error) {
	request := tdmq.NewDescribeRocketMQClustersRequest()
	request.Offset = common.Uint64Ptr(0)
	request.Limit = common.Uint64Ptr(1000)
	if strings.TrimSpace(id) != "" {
		request.IdKeyword = common.StringPtr(id)
	}
	if strings.TrimSpace(name) != "" {
		request.NameKeyword = common.StringPtr(name)
	}
	response, err := r.clientV4.DescribeRocketMQClusters(request)
	if err != nil {
		return
	}
	for _, item := range response.Response.ClusterList {
		c := item.Config
		info := item.Info
		list = append(list, models.RocketMQItemV4{
			ClusterId:                *info.ClusterId,
			ClusterName:              *info.ClusterName,
			Region:                   *info.Region,
			CreateTime:               *info.CreateTime,
			Remark:                   *info.Remark,
			PublicEndPoint:           *info.PublicEndPoint,
			VpcEndPoint:              *info.VpcEndPoint,
			SupportNamespaceEndpoint: *info.SupportNamespaceEndpoint,
			IsVip:                    *info.IsVip,
			RocketMQFlag:             *info.RocketMQFlag,
			Status:                   *info.Status,
			//IsolateTime:              *info.IsolateTime,
			HttpPublicEndpoint: *info.HttpPublicEndpoint,
			HttpVpcEndpoint:    *info.HttpVpcEndpoint,
			//InternalEndpoint:     *info.InternalEndpoint,
			//HttpInternalEndpoint: *info.HttpInternalEndpoint,
			MaxTpsPerNamespace: *c.MaxTpsPerNamespace,
			MaxNamespaceNum:    *c.MaxNamespaceNum,
			UsedNamespaceNum:   *c.UsedNamespaceNum,
			MaxTopicNum:        *c.MaxTopicNum,
			UsedTopicNum:       *c.UsedTopicNum,
			MaxGroupNum:        *c.MaxGroupNum,
			UsedGroupNum:       *c.UsedGroupNum,
			MaxRetentionTime:   *c.MaxRetentionTime,
			MaxLatencyTime:     *c.MaxLatencyTime,
			MaxQueuesPerTopic:  *c.MaxQueuesPerTopic,
		})
	}
	return
}
